package www.hz.infrastructure.repository;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RBlockingQueue;
import org.redisson.api.RDelayedQueue;
import org.redisson.api.RQueue;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Repository;
import www.hz.domain.strategy.model.entity.StrategyAwardEntity;
import www.hz.domain.strategy.model.entity.StrategyEntity;
import www.hz.domain.strategy.model.entity.StrategyRuleEntity;
import www.hz.domain.strategy.model.valobj.*;
import www.hz.domain.strategy.model.vo.StrategyAwardRuleModelVO;
import www.hz.domain.strategy.repository.IStrategyRepository;
import www.hz.domain.strategy.service.armory.StrategyArmory;
import www.hz.infrastructure.dao.*;
import www.hz.infrastructure.dao.po.*;
import www.hz.infrastructure.redis.IRedisService;
import www.hz.types.common.Constants;
import www.hz.types.exception.AppException;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.TimeUnit;

import static www.hz.types.enums.ResponseCode.UN_ASSEMBLED_STRATEGY_ARMORY;

/**
 * @className: StrategyRepository
 * @Description: TODO
 * @version: v1.８.0
 * @author: hz
 * @date: 2025/2/6 16:45
 */
@Repository
@Slf4j
public class StrategyRepository implements IStrategyRepository {
    @Resource
    private IRuleTreeDao  ruleTreeDao;
    @Resource
    private IRuleTreeNodeDao  ruleTreeNodeDao;
    @Resource
    private IRuleTreeNodeLineDao  ruleTreeNodeLineDao;
    @Resource
    private IStrategyRule  strategyRuleDao;
    @Resource
    private IStrategy  strategyDao;
    @Resource
    private IStrategyAward strategyAwardDao;
    @Resource
    private IRedisService  redisService;
    @Override
    public List<StrategyAwardEntity> queryStrategyAwardList(Long strategyId) {
        //先查看redis缓存
        String CacheKey = Constants.RedisKey.STRATEGY_AWARD_LIST_KEY+strategyId;
        List<StrategyAwardEntity>  strategyAwardEntities = redisService.getValue(CacheKey);
        if(strategyAwardEntities!=null&&!strategyAwardEntities.isEmpty()) return strategyAwardEntities;
        //查询数据库
        List<StrategyAward> strategyAwards = strategyAwardDao.queryStrategyAwardListBystrategyId(strategyId);
        strategyAwardEntities  = new ArrayList<>(strategyAwards.size());
        for (StrategyAward strategyAward : strategyAwards) {
            StrategyAwardEntity strategyAwardEntity = StrategyAwardEntity.builder()
                    .strategyId(strategyAward.getStrategyId())
                    .awardId(strategyAward.getAwardId())
                    .awardTitle(strategyAward.getAwardTitle())
                    .awardSubtitle(strategyAward.getAwardSubtitle())
                    .awardCount(strategyAward.getAwardCount())
                    .awardCountSurplus(strategyAward.getAwardCountSurplus())
                    .awardRate(strategyAward.getAwardRate())
                    .sort(strategyAward.getSort())
                    .ruleModels(strategyAward.getRuleModels())
                    .build();
            strategyAwardEntities.add(strategyAwardEntity);
        }
      redisService.setValue(CacheKey,strategyAwardEntities);


        return strategyAwardEntities;
    }

    @Override
    public <K, V> void storeStrategyAwardSearchRateTable(String key, Integer Range, Map<K, V> strategyAwardSearchRateTable) {
        // 1. 存储抽奖策略范围值，如10000，用于生成1000以内的随机数
        redisService.setValue(Constants.RedisKey.STRATEGY_RATE_RANGE_KEY + key, Range);
        // 2. 存储概率查找表 - 存在则删除重新装配
        String tableCacheKey = Constants.RedisKey.STRATEGY_RATE_TABLE_KEY + key;
        if (redisService.isExists(tableCacheKey)) {
            redisService.remove(tableCacheKey);
        }
        Map<Integer, Integer> cacheRateTable = redisService.getMap(Constants.RedisKey.STRATEGY_RATE_TABLE_KEY + key);
        cacheRateTable.putAll((Map<? extends Integer, ? extends Integer>) strategyAwardSearchRateTable);
    }

    @Override
    public <K, V> Map<K, V> getMap(String key) {
        return null;
    }

    @Override
    public Integer getStrategyAwardAssemble(String key, Integer rateKey) {
        return redisService.getFromMap(Constants.RedisKey.STRATEGY_RATE_TABLE_KEY + key, rateKey);
    }

    @Override
    public int getRateRange(Long strategyId) {
        return redisService.getValue(Constants.RedisKey.STRATEGY_RATE_RANGE_KEY+strategyId);
    }

    @Override
    public int getRateRange(String key) {
        String cacheKey = Constants.RedisKey.STRATEGY_RATE_RANGE_KEY + key;
        if (!redisService.isExists(cacheKey)) {
            throw new AppException(UN_ASSEMBLED_STRATEGY_ARMORY.getCode(), cacheKey + Constants.COLON + UN_ASSEMBLED_STRATEGY_ARMORY.getInfo());
        }
        return redisService.getValue(cacheKey);
    }

    @Override
    public String queryStrategyRuleValue(Long strategyId, String ruleModel) {

        return queryStrategyRuleValue(strategyId,null,ruleModel);
    }

    @Override
    public String queryStrategyRuleValue(Long strategyId, Integer awardId, String ruleModel) {
        //查缓存
        String cacheKey=Constants.RedisKey.STRATEGY_RULE_WEIGHT_KEY+strategyId+awardId+ruleModel;
        StrategyRuleEntity strategyRuleEntity=redisService.getValue(cacheKey);
        if (strategyRuleEntity!=null) return strategyRuleEntity.getRuleValue();
        //查数据库
        StrategyRule strategyRule=strategyRuleDao.queryStrategyrule(strategyId,ruleModel);
        if (strategyRule==null) throw new AppException("策略规则不存在");
        strategyRuleEntity=StrategyRuleEntity.builder()
                .strategyId(strategyRule.getStrategyId())
                .awardId(strategyRule.getAwardId())
                .ruleType(strategyRule.getRuleType())
                .ruleModel(strategyRule.getRuleModel())
                .ruleValue(strategyRule.getRuleValue())
                .ruleDesc(strategyRule.getRuleDesc())
                .build();
        //存缓存
        redisService.setValue(cacheKey,strategyRuleEntity);
        return strategyRuleEntity.getRuleValue();
    }

    @Override
    public RuleTreeVO queryRuleTreeVOByTreeId(String treeId) {
        //查缓存
        String cacheKey=Constants.RedisKey.RULE_TREE_VO_KEY+treeId;
        RuleTreeVO  ruleTreeVOCache=redisService.getValue(cacheKey);
        if (ruleTreeVOCache!=null) return ruleTreeVOCache;
        //查数据库
        RuleTree ruleTree = ruleTreeDao.queryRuleTreeByTreeId(treeId);
        List<RuleTreeNode> ruleTreeNodes = ruleTreeNodeDao.queryRuleTreeNodeListByTreeId(treeId);
        List<RuleTreeNodeLine> ruleTreeNodeLines = ruleTreeNodeLineDao.queryRuleTreeNodeLineListByTreeId(treeId);
        //1.treenodeline转化为map结构
        Map<String, List<RuleTreeNodeLineVO>>  ruleTreeNodeLineMap =new HashMap<>();
        for (RuleTreeNodeLine  ruleTreeNodeLine:ruleTreeNodeLines){
            RuleTreeNodeLineVO ruleTreeNodeLineVO = RuleTreeNodeLineVO.builder()
                    .ruleNodeTo(ruleTreeNodeLine.getRuleNodeTo())
                    .ruleNodeFrom(ruleTreeNodeLine.getRuleNodeFrom())
                    .ruleLimitValue(RuleLogicCheckTypeVO.valueOf(ruleTreeNodeLine.getRuleLimitValue()))
                    .ruleLimitType(RuleLimitTypeVO.valueOf(ruleTreeNodeLine.getRuleLimitType()))
                    .build();
            ruleTreeNodeLineMap
                    .computeIfAbsent(ruleTreeNodeLine.getRuleNodeFrom(), k -> new ArrayList<>())
                    .add(ruleTreeNodeLineVO);
        }
        //2.treenode转化为Map结构
        Map<String, RuleTreeNodeVO> ruleTreeNodeMap = new HashMap<>();
        for (RuleTreeNode ruleTreeNode:ruleTreeNodes){
            RuleTreeNodeVO ruleTreeNodeVO = RuleTreeNodeVO.builder()
                    .treeId(ruleTreeNode.getTreeId())
                    .ruleKey(ruleTreeNode.getRuleKey())
                    .ruleDesc(ruleTreeNode.getRuleDesc())
                    .ruleValue(ruleTreeNode.getRuleValue())
                    .treeNodeLineVOList(ruleTreeNodeLineMap.get(ruleTreeNode.getRuleKey()))
                    .build();
            ruleTreeNodeMap.put(ruleTreeNode.getRuleKey(), ruleTreeNodeVO);
        }
        //3.构建ruletree
        RuleTreeVO ruleTreeVODB = RuleTreeVO.builder()
                .treeId(ruleTree.getTreeId())
                .treeName(ruleTree.getTreeName())
                .treeDesc(ruleTree.getTreeDesc())
                .treeRootRuleNode(ruleTree.getTreeRootRuleKey())
                .treeNodeMap(ruleTreeNodeMap)
                .build();
        return ruleTreeVODB;
    }

    @Override
    public void cacheStrategyAwardCount(String cacheKey, Integer awardCount) {
      if (redisService.isExists(cacheKey)) return;
      redisService.setAtomicLong(cacheKey,awardCount);
    }

    @Override
    public Boolean subtractionAwardStock(String cacheKey) {
        Long surplus = redisService.decr(cacheKey);
        if (surplus<0){
            redisService.setValue(cacheKey,0);
            return false;
        }
        String lockKey=cacheKey+Constants.UNDERLINE+surplus;
        Boolean lock = redisService.setNx(lockKey);
        if (!lock){
            log.info("策略奖品库存枷锁失败{}",lockKey);
        }

        return lock;
    }

    @Override
    public Boolean subtractionAwardStock(String cacheKey, Date endDateTime) {
        return null;
    }

    @Override
    public void awardStockConsumeSendQueue(StrategyAwardStockKeyVO strategyAwardStockKeyVO) {
      String cacheKey=Constants.RedisKey.STRATEGY_AWARD_COUNT_QUERY_KEY;
        RBlockingQueue<StrategyAwardStockKeyVO> blockingQueue = redisService.getBlockingQueue(cacheKey);
        RDelayedQueue<StrategyAwardStockKeyVO> delayedQueue = redisService.getDelayedQueue(blockingQueue);
        delayedQueue.offer(strategyAwardStockKeyVO,3, TimeUnit.SECONDS);
    }

    @Override
    public StrategyAwardStockKeyVO takeQueueValue() throws InterruptedException {
        String cacheKey = Constants.RedisKey.STRATEGY_AWARD_COUNT_QUERY_KEY;
        RBlockingQueue<StrategyAwardStockKeyVO> destinationQueue = redisService.getBlockingQueue(cacheKey);
        return destinationQueue.poll();
    }

    @Override
    public void updateStrategyAwardStock(Long strategyId, Integer awardId) {
        StrategyAward strategyAward = new StrategyAward();
        strategyAward.setStrategyId(strategyId);
        strategyAward.setAwardId(awardId);
        strategyAwardDao.updateStrategyAwardStock(strategyAward);
    }

    @Override
    public StrategyAwardEntity queryStrategyAwardEntity(Long strategyId, Integer awardId) {
        //查缓存
        String cacheKey=Constants.RedisKey.STRATEGY_AWARD_KEY+strategyId+Constants.UNDERLINE+awardId;
        StrategyAwardEntity strategyAwardEntity = redisService.getValue(cacheKey);
        if (strategyAwardEntity!=null) return strategyAwardEntity;
        //查数据库
        StrategyAward strategyAward=strategyAwardDao.queryStrategyAward(strategyId,awardId);
        strategyAwardEntity = StrategyAwardEntity.builder()
                .strategyId(strategyAward.getStrategyId())
                .awardId(strategyAward.getAwardId())
                .awardTitle(strategyAward.getAwardTitle())
                .awardSubtitle(strategyAward.getAwardSubtitle())
                .awardCount(strategyAward.getAwardCount())
                .awardCountSurplus(strategyAward.getAwardCountSurplus())
                .awardRate(strategyAward.getAwardRate())
                .sort(strategyAward.getSort())
                .build();
        // 缓存结果
        redisService.setValue(cacheKey, strategyAwardEntity);
        // 返回数据
        return strategyAwardEntity;
    }

    @Override
    public Long queryStrategyIdByActivityId(Long activityId) {
        return null;
    }

    @Override
    public Integer queryTodayUserRaffleCount(String userId, Long strategyId) {
        return null;
    }

    @Override
    public Map<String, Integer> queryAwardRuleLockCount(String[] treeIds) {
        return null;
    }

    @Override
    public Integer queryActivityAccountTotalUseCount(String userId, Long strategyId) {
        return null;
    }

    @Override
    public void cacheStrategyArmoryAlgorithm(String key, String beanName) {

    }

    @Override
    public String queryStrategyArmoryAlgorithmFromCache(String key) {
        return null;
    }

    @Override
    public StrategyEntity queryStrategyEntityByStrategyId(Long strategyId) {
            String cacheKey = Constants.RedisKey.STRATEGY_KEY + strategyId;
            StrategyEntity strategyEntity = redisService.getValue(cacheKey);
            if (null != strategyEntity) return strategyEntity;
            Strategy strategy = strategyDao.queryStrategyByStrategyId(strategyId);
            if (null == strategy) return StrategyEntity.builder().build();
            strategyEntity = StrategyEntity.builder()
                    .strategyId(strategy.getStrategyId())
                    .strategyDesc(strategy.getStrategyDesc())
                    .ruleModels(strategy.getRuleModels())
                    .build();
            redisService.setValue(cacheKey, strategyEntity);
            return strategyEntity;
        }


    @Override
    public StrategyRuleEntity queryStrategyRule(Long strategyId, String ruleModel) {
        StrategyRule strategyRule = strategyRuleDao.queryStrategyrule(strategyId, ruleModel);

        return StrategyRuleEntity.builder()
                .strategyId(strategyRule.getStrategyId())
                .awardId(strategyRule.getAwardId())
                .ruleType(strategyRule.getRuleType())
                .ruleModel(strategyRule.getRuleModel())
                .ruleValue(strategyRule.getRuleValue())
                .ruleDesc(strategyRule.getRuleDesc())
                .build();
    }

    @Override
    public StrategyAwardRuleModelVO queryStrategyAwardRuleModelVO(Long strategyId, Integer awardId) {
        StrategyAward strategyAward = strategyAwardDao.queryStrategyAward(strategyId, awardId);
        if (StringUtils.isBlank(strategyAward.getRuleModels())) return null;
        return StrategyAwardRuleModelVO.builder().ruleModels(strategyAward.getRuleModels()).build();
    }

    @Override
    public String queryRuleValue(Long strategyId, Integer awardId, String ruleModel) {
        String ruleValue = strategyRuleDao.queryRuleValue(strategyId, awardId,ruleModel);
        return ruleValue;
    }
}